package impl

import (
	"context"

	"gitee.com/liuxiaowei123/vblog-3/app/token"
	"gitee.com/liuxiaowei123/vblog-3/app/user"
	"gitee.com/liuxiaowei123/vblog-3/conf"
	"gitee.com/liuxiaowei123/vblog-3/exception"
	"gitee.com/liuxiaowei123/vblog-3/ioc"
	"gorm.io/gorm"
)

type TokenServiceImpl struct {
	usi user.UserService
	db  *gorm.DB
}

// 把TokenServiceImpl 对象注册到ioc中
func init() {
	ioc.Controller().Registry(&TokenServiceImpl{})
}

// TokenServiceImpl对象实现Object接口函数，完成初始化
func (t *TokenServiceImpl) Init() {
	t.usi = ioc.Controller().Get(user.Appname).(user.UserService)
	t.db = conf.C.Mysql.Getconn().Debug()
}

// TokenServiceImpl对象实现Object接口函数
func (t *TokenServiceImpl) Name() string {
	return token.Appname
}

func NewTokenServiceImpl(userimpl user.UserService) *TokenServiceImpl {
	return &TokenServiceImpl{
		usi: userimpl,
		db:  conf.C.Mysql.Getconn().Debug(),
	}
}

// 登录后颁发token
func (t *TokenServiceImpl) Login(c context.Context, req *token.LoginRequest) (*token.Token, error) {
	// 1、查询用户
	d := user.NewDescribeByUsername(req.Username)
	u, err := t.usi.DescribeUser(c, d)
	if err != nil {
		return nil, exception.NewAuthFailed("用户名或密码不正确")
	}
	// 2、校验密码
	err = u.CheckPassword(req.Password)
	if err != nil {
		return nil, exception.NewAuthFailed("用户名或密码不正确")
	}

	// 3、颁发token，也就是构造token实例
	tk := token.NewToken()
	tk.UserName = req.Username
	tk.UserId = u.Id

	// 4、保存token
	err = t.db.WithContext(c).Create(tk).Error
	if err != nil {
		return nil, err
	}

	// 5、返回token
	return tk, nil
}

// 退出后销毁token
func (t *TokenServiceImpl) Logout(c context.Context, req *token.LogoutRequest) error {
	return nil
}

// 校验token
func (t *TokenServiceImpl) Validate(c context.Context, req *token.ValidateRequest) (*token.Token, error) {
	// 1、查询token是否存在
	ins := token.NewToken()
	err := t.db.WithContext(c).Where("access_token = ?", req.AccessToken).First(ins).Error
	if err != nil {
		return nil, exception.NewNotFound("没有查询到token")
	}
	// 2、校验token是否过期
	err = ins.IsExpiredTime()
	if err != nil {
		return nil, err
	}

	// 3、返回token
	return ins, nil
}
